borderlandsfandomcom_ru-20200214-history
Модуль:Nutils
--local hasc = require('Dev:Pageinfo') --local getArgs = require("Dev:Arguments").getArgs local p = {} function p.hello( frame ) local nt = '' nt = nt .. ' element1 ' return nt --"Hello, world!" end --hello function p.tst (frame) local args = frame.args or frame return p.hasbit(3, p.bit(1)) end --tst function p.tst2 (frame) local arg1 = frame.args1 local ns = '' local ns1 = '' --ns = '[.. args[1 .. ']]' --ns = arg1 --ns = frame:newParserValue(ns):expand() --ns = frame:preprocess(ns) for i = 1, mw.ustring.len(ns) do ns1 = ns1..'_'..mw.ustring.sub(ns, i, i) end ns = ns .. ns1 return ns end --tst2 function p.rainbow (frame) -- draws rainbow text if not frame or not frame.args then return end -- debug console defence -- get frame.args if arg1 or frame:parent.args local args = frame.args if not args'1' or not args1 then args = (frame.getParent and frame:getParent() or frame).args end local text = args'1' or args1 if not text then return '' end local ret = {}-- table is fastest way to deal with strings local linkIndex, _, linkHead, linkLink, linkAlias, linkTail = text:find('(.-)%[%[(^]-)|(^]+)%]%](.*)', 1, false) if linkIndex then table.insert(ret, linkHead or ) table.insert(ret, '') table.insert(ret, rainbowize(linkAlias)) table.insert(ret, '') table.insert(ret, linkTail or '') else return rainbowize(text) end return table.concat(ret) end-- rainbow function rainbowize (text) -- rainbowize the text if not text then return '' end -- color array: red, orange, yellow, greenyellow, cyan, deepskyblue, violet local rainbow = {'#ff0000', '#ffa500', '#ffff00', '#adff2f', '#00ffff', '#00bfff', '#ee82ee'} local spanHead = '' local spanTail = '' local ret = {}-- table is fastest way to deal with strings for index, character in ipairs(mw.text.split(text, '')) do local pos = math.fmod(index, #rainbow) -- if pos 0 (last element of the table) then return last el pos = pos ~= 0 and pos or #rainbow table.insert(ret, spanHead)-- open span table.insert(ret, rainbowpos)-- add color table.insert(ret, spanHeadC)-- close opening table.insert(ret, character)-- add character table.insert(ret, spanTail)-- close span end return table.concat(ret) end-- rainbowize function p.setCatLocation (frame) --set category by location --1: location: location --2: prefix: prefix --3: postfix: postfix local args = frame.args or frame local location = args.location or args'1' or args1 if (not location) or (#location 0) then return end local prefix = args.prefix or args'2' or args2 or '' local postfix = args.postfix or args'3' or args3 or '' --only 1 location permitted is local s = mw.ustring.find(location, ',') or mw.ustring.find(location, '%]%].+%]%]') if s then return end --remove [] location = mw.ustring.match(location, '%[*(^%|]+)%]*') if not location then return end location = 'category:' .. prefix .. location .. postfix .. '' return frame.preprocess and frame:preprocess(location) or location end--setcatlocation function p.getInterwiki (frame) --returns interwiki link for lang --format: lang:(link or default)|alias --1: lang; 2: alias; 3: default link local title = mw.title.getCurrentTitle() local content = title:getContent() local args = frame.args local lang = args'1' or args1 local alias = args'2' or args2 local default = args'3' or args3 -- new page = no content if (not lang) or (not content) then return (alias or default) end local s, re, c1st, mtch c1st = mw.ustring.sub(lang, 1, 1) re = '%[%[.. mw.ustring.upper(c1st) .. mw.ustring.lower(c1st) .. '' .. mw.ustring.lower(mw.ustring.sub(lang, 2)) .. ':(^-)%]%]' mtch = mw.ustring.match(content, re) if #mw.text.trim(alias or '') 0 then alias = mtch end s = '' .. (alias or default) .. '' return s end --getinterwiki function p.hasInterwiki (frame) --returns link if page has lang interwiki --1: lang local title = mw.title.getCurrentTitle() -- do not try to process new page if not title then return end local content = title:getContent() if not content then return end local args = frame.args local lang = args'1' or args1 if not lang then return end local re, c1st c1st = mw.ustring.sub(lang, 1, 1) re = '%[%[.. mw.ustring.upper(c1st) .. mw.ustring.lower(c1st) .. '' .. mw.ustring.lower(mw.ustring.sub(lang, 2)) .. ':(^-)%]%]' return mw.ustring.match(content, re) end --hasinterwiki function p.ifex (frame) --returns: or page or category:name or pa1 --opt is a bitwise container --name/1: pagename, opt: options local args = frame.args or frame local name = args'name' or args'1' or args1 or '' local ns = args'ns' or '' --namespace local nsn = '' --namespaced name local alt = args'alt' or '' --alt text local tail = args'tail' or '' --tail if tail ~= '' then tail = ' ' .. tail end --opt: 1: do not search for category; 2: do not return }; 3: both local opt = tonumber(args'opt') or 0 --parent args local parent if frame and frame.getParent then parent = frame:getParent() else parent = frame end --local parent = p.iif(frame.getParent, frame:getParent(), frame) local pargs = parent.args or parent local pa1, pa2, pa3 = pargs'1' or pargs1 or '', pargs'2' or pargs2 or '', pargs'3' or pargs3 or '' -- pa1}}| --nothing found, make red link local ret = name .. tail --' |1=' .. pa1 .. '}}| |' .. pa1 .. '}}' --params local p1, p2, p3 = args'p1' or '', args'p2' or '', args'p3' or '' --local ret = isfalse if p.hasbit(opt, p.bit(2)) then --do not return } ret = '' end if name ~= '' then --capitalize name name = mw.ustring.upper(mw.ustring.sub(name, 1, 1)) .. mw.ustring.sub(name, 2) --normalize name = mw.ustring.gsub(name, '_', ' ') if ns ~= '' then nsn = mw.ustring.upper(mw.ustring.sub(ns, 1, 1)) .. mw.ustring.sub(ns, 2) .. ':' .. name end local data = mw.loadData('module:Nbigbigdatabig') if nsn ~= '' and datansn then if ns 'Шаблон' or ns 'Template' then -- template --ret = }| }| }}} ret = ' ' .. tail else ret = '[[' .. nsn .. p.iif(alt~=, '|' .. alt, ) .. ']]' .. tail end elseif dataname then --page in ns:0 --ret = ' }}}| }|2}} }|3}}' --ret = '1=' .. pa1 .. '}}| ' ret = '[[' .. name .. p.iif(alt~=, '|' .. alt, ) .. ']]' .. tail elseif not p.hasbit(opt, p.bit(1)) then --category local scat = p.ifexc({1=name, 2=alt, 3=tail, 'opt'=1}) if scat ~= '' then ret = scat end end end if frame and frame.preprocess then return frame:preprocess(ret) else return ret end end --ifex function p.ifexc (frame) --ifexist for category --opt is a bitwise container --returns alt tail or name or '' if opt:1 --or alt tail if opt:2 local args = frame.args or frame local name = args'name' or args'1' or args1 or '' local alt = args'alt' or args'2' or args2 or '' local tail = args'tail' or args'3' or args3 or '' if tail ~= '' then tail = ' ' .. tail end --opt: 1: do not return }; 2: set cat cat:... local opt = tonumber(args'opt') or 0 local ret = '' if p.hasbit(opt, p.bit(1)) then ret = '' else if p.hasbit(opt, p.bit(2)) then ret = 'Категория:' .. name .. tail else ret = name .. tail end end if name ~= '' then --capitalize name name = mw.ustring.upper(mw.ustring.sub(name, 1, 1)) .. mw.ustring.sub(name, 2) --normalize name = mw.ustring.gsub(name, '_', ' ') local data = mw.loadData('module:nbigdatacat') if dataname then if p.hasbit(opt, p.bit(2)) then ret = '[[Категория:' .. name .. p.iif(alt~=, '|' .. alt, ) .. ']]' .. tail else ret = '[[:Категория:' .. name .. p.iif(alt~=, '|' .. alt, ) .. ']]' .. tail end end end if frame and frame.preprocess then return frame:preprocess(ret) else return ret end end function p.th (frame) --transclude header --according to template:th --excepts 1st param (t) -> params shifted local args = frame.args local ns, ncontent, npattern = '' local ncount = tonumber(args'c' or args3) or 0 local ntitle = args'd' or args1 --ncount = tonumber(ncount) --if type(args't') ~= 'nil' then ns=args't' elseif type(args1) ~= 'nil' then ns=args1 end if ((args'bylink' or args5 or '1') '0') then ncontent = (ntitle) else ncontent = frame:expandTemplate{ title=':' .. ntitle } end npattern = (args'h' or args2 or 'Описание') if ncount 0 then npattern = '=+' .. npattern .. '=+(.-) ' else npattern = '=+' .. npattern .. '.-%.-=*(' .. mw.ustring.rep('%w%s,:;%-%+%<%>+%<%>%.%?%!%C+', ncount) .. ')' end ncontent = mw.ustring.match(ncontent, npattern) if type(ncontent) 'nil' then ns = ns .. 'Категория:th - Ошибка поиска' .. (args'def' or args4 or '') else ns = ns .. mw.ustring.gsub(ncontent, '<^>*>', '') end ns = frame:preprocess(ns) return ns end --th function p.th2 (frame) --faster (x5-x7), but uses expensive parser function (title*) --transclude header --according to template:th --excepts 1st param (t) -> params shifted local args = frame.args or frame local ns, ncontent, npattern = '', '' local pname = args'd' or args'1' or args1 local pheader = args'h' or args'2' or args2 or 'Описание' local pcount = tonumber(args'c' or args'3' or args3) or 0 local pdef = args'def' or args'4' or args4 or '' local pbylink = (args'bylink' or args'5' or args5 or '1') ~= '0' local ntitle if not pbylink then ncontent = pname else ntitle = mw.title.new(pname) if type(ntitle) ~= 'nil' then ncontent = ntitle:getContent() else ncontent = frame:expandTemplate{ title=':' .. pname } end end npattern = pheader if pcount 0 then npattern = '=+' .. npattern .. '=+(.-) ' else npattern = '=+' .. npattern .. '.-%.-=*(' .. mw.ustring.rep('%w%s,:;%-%+%<%>+%<%>%.%?%!%C+', pcount) .. ')' end ncontent = mw.ustring.match(ncontent, npattern) if type(ncontent) 'nil' then ns = ns .. 'Категория:th - Ошибка поиска' .. pdef else ns = ns .. mw.ustring.gsub(ncontent, '<^>*>', '') end if frame.preprocess then ns = frame:preprocess(ns) end --ns=mw.ustring.gsub(ns, '%z', '') --remove zero-char's return ns --frame:preprocess(ns) end --th2 function p.th3 (frame) --tst local args = frame.args local ns, ncontent, npattern = '', '' local ncount = tonumber(args'c' or args3) or 0 local ntitle --ncount = tonumber(ncount) --if type(args't') ~= 'nil' then ns=args't' elseif type(args1) ~= 'nil' then ns=args1 end if ((args'bylink' or args5 or '1') '0') then ncontent=(args'd' or args1) else ntitle=mw.title.new(args'd' or args1) if type(ntitle) ~= 'nil' then ncontent = ntitle:getContent() else ncontent = frame:expandTemplate{ title=':' .. (args'd' or args1) } end end npattern = (args'h' or args2 or 'Описание') if ncount 0 then npattern = '=+' .. npattern .. '=+(.-) ' else npattern = '=+' .. npattern .. '=+' .. '(' .. mw.ustring.rep('.-%.%?%!+%s+', ncount) .. ')=$*' end ncontent = mw.ustring.match(ncontent, npattern) if type(ncontent) 'nil' then ns = ns .. 'Категория:th - Ошибка поиска' .. (args'def' or args4 or '') else ns = ns .. mw.ustring.gsub(ncontent, '<^>*>', '') end ns = frame:preprocess(ns) --ns=mw.ustring.gsub(ns, '%z', '') --remove zero-char's return ns --frame:preprocess(ns) end --th3 function p.setcat (frame) --set category by content --1: page; 2,3: text; 4: cat if found; 5: cat if not found local args = frame.args local t1, t2 = args2, args3 local nh = '' local ptitle = mw.title.new(args1) local pcontent = mw.getCurrentFrame():preprocess(' ') --nh=mw.ustring.len(pcontent) if type(args3) 'nil' then t2 = t1 end if mw.ustring.find(pcontent, t2, 1, true) or mw.ustring.find(pcontent, t3, 1, true) then nh = args4 else nh = args5 end --nh=(ptitle.prefixedText or 'nil') --nh=#pcontent --nh = hasc.hascat(frame) --nh = select('#', args) return nh--..','..args1..','..(args2 or 'nil')..','..(args3 or 'nil')..','..(args4 or 'nil') end --setcat function p.cats (frame) --has category local hasc = require('Dev:Pageinfo') local args = frame.args local nh nh = hasc.hascat(frame) --nh = select('#', args) return args1..','..(nh or 'nil') end --cats function parseLinks(data, part) -- returns {links} w\o [[]] -- part: which part of title to return: link, title -- part table: {link: link, title: title} if not data then return {} end local links = {} local patLink = '%[%[(^]*)%]%]'-- link pattern part = part or '' function splitLink(link) -- раздирает ссылки на части local al = mw.text.split(link, '|') if part 'link' then link = (#al > 0 and #mw.text.trim(al1) > 0) and al1 or nil elseif part 'title' then link = #al > 1 and table.concat(al, '|', 2) or (#mw.text.trim(al1) > 0 and al1 or nil) elseif part 'table' then if #al > 0 and #mw.text.trim(al1) > 0 then link = { link = al1, title = #al > 1 and table.concat(al, '|', 2) or al1 } else link = nil end end return link end-- splitlink function parseLinkHelper(t) -- нужна для избежания дублирования кода, -- если на выпарсивание ссылок передали массив строк -- пользуется переменными родителя local ret = {} for l in t:gmatch(patLink) do l = splitLink(l) if l then table.insert(ret, l) end end if #ret 0 then -- no links (loc w\o [[]]: sanctuary instead of sanctuary) t = splitLink(t) table.insert(ret, t) end return ret end-- parselinkhelper if type(data) 'table' then -- пришёл массив строк for _, v in pairs(data) do -- все найденные ссылки собираются на одном уровне for _, v1 in pairs(parseLinkHelper(v)) do table.insert(links, v1) end end else links = parseLinkHelper(data) end-- if data table return links end-- parselinks function tableTrim(tab) -- removes zero/empty values from the table if #(tab or {}) 0 then return tab end local i = 1 repeat if #(tabi or {}) 0 or #mw.text.trim(tabi) 0 then table.remove(tab, i) else i = i + 1 end until i > #tab return tab end-- tabletrim function tableSort(el1, el2) -- sane table sorting alg ("str" is lesser than "str - str") -- strip [] el1 = mw.ustring.gsub(el1, '[%%]', '') el2 = mw.ustring.gsub(el2, '[%%]', '') if (#el1 < #el2) and (mw.ustring.sub(el2, 1, #el1) el1) then -- if el2 includes el1, then el is lesser return el1 elseif (#el2 < #el1) and (mw.ustring.sub(el1, 1, #el2) el2) then -- if el1 includes el2, then el2 is lesser return el2 else -- otherwise: just < return el1 < el2 end end-- tablesort function p.tlm (frame) --template:tlocmission local args = frame.args or frame local tfull = args'1' or args1 or 'В этом разделе указаны задания, связанные с данной локацией. В разделе "Выдаются" указаны задания, которые берут начало в этой локации; а в разделе "Выполняются" находятся задания, для которых данная локация служит промежуточной или конечной.' local tin = args'2' or args2 or 'В этом разделе указаны задания, которые берут начало в этой локации.' local tout = args'3' or args3 or 'В этом разделе указаны задания, для которых данная локация служит промежуточной или конечной.' local nret = args'4' or args4 or tfull -- default local ntitle = mw.title.new((args.p and #args.p > 0) and args.p or mw.title.getCurrentTitle().text) local mode = args.mode or '' -- auto для автосписка миссий local game = mw.text.trim(args.game or '') -- игра game = #game > 0 and game or nil if mode 'auto' then -- автоматический список миссий local nret1 = {} local dplText = ' ' local tnoresult = 'В этом разделе были бы указаны задания, связанные с данной локацией. Если бы их удалось найти.' local there = ' (выполняется здесь же)' -- дополнительные миссии (которые невозможно найти автоматически) -- формат: миссия1~~миссия2 local addStart = tableTrim(mw.text.split(args.astart or '', '~~')) local addEnd = tableTrim(mw.text.split(args.aend or '', '~~')) -- миссии, которые начинаются\заканчиваются здесь local mstart = addStart local mend = addEnd -- defend dpl against stupid chars in the title (<>) -- вызов всегда должен быть через mw.ustring, чтобы получить ustring вместо string -- баг?: ustring должен быть на каждой строке по дефолту local linksto = mw.ustring.gsub(ntitle.text, '«<>»', '%') local includematch = mw.ustring.gsub(ntitle.text, '(()/)', '\\%1') -- .*?: потенциально фейловый паттерн: может гребануть больше, чем надо -- на практике пока не встречалось includematch = mw.ustring.gsub(includematch, '«<>»', '.*?') includematch = mw.ustring.gsub(includematch, '[ _]', '[ _]') dplText = mw.ustring.gsub(dplText, '%%PAGENAME1%%', linksto) dplText = mw.ustring.gsub(dplText, '%%PAGENAME2%%', includematch) -- тестовые данные; не предназначены для полной проверки без указания параметра p (плохой формат, -список миссий) local dplResult = frame.preprocess and frame:preprocess(dplText) or [=повелитель |~Дожигатель |~[[Дожигатель] и Упавший Гелиос |~Borderlands 2~~Друзья на всю жизнь (задание) |~Дожигатель |~Развалины Даль, Норы, Упавший Гелиос и Исследовательский центр "Скарабей" |~Borderlands 2~~Защитник (задание) |~Дожигатель |~Развалины Даль |~Borderlands 2~~Клятва Гиппократа |~Дожигатель |~Развалины Даль |~Borderlands 2~~Клятва Гиппократа - Глава 2 |~Дожигатель |~Норы |~Borderlands 2~~Концертная приманка |~Дожигатель |~Гудящая Бездна |~Borderlands 2~~Космический ковбой |~Дожигатель |~Развалины Даль |~Borderlands 2~~Мой хрупкий пони |~Дожигатель |~Упавший Гелиос |~Borderlands 2~~Охотник Вон |~Дожигатель |~Норы |~Borderlands 2~~Поиск образцов |~Дожигатель |~Развалины Даль |~Borderlands 2~~Правитель Вон |~Дожигатель |~Развалины Даль |~Borderlands 2~~Сиренология |~Дожигатель |~Упавший Гелиос |~Borderlands 2~~Точка преткновения |~Дожигатель |~Норы |~Borderlands 2]=] nret = tnoresult if dplResult and #dplResult > 0 then -- do stuff -- parse dpl output -- ~~title (mission)|~loc1|~loc2|~game local dplLines = mw.text.split(dplResult, '~~') -- распарсенный список "выполняющихся" миссий -- в связи с особенностями заполнения шаблона делать такое же -- для "выдающихся" смысла пока что нет local addEndParsed = parseLinks(addEnd, 'table') -- remove 1st empty row (cuz ~~data -> {, data}) table.remove(dplLines, 1) function findLoc(locs, loc) -- find loc in locs -- returns loc index or nil for i, v in ipairs(locs) do if v.link loc.link then return i end end return nil end--findloc for _, line in ipairs(dplLines) do local mis, loc1, loc2, gam = line:match('^%s%c~*(.-)%s%c*|~(.-)%s%c*|~(.-)%s%c*|~(.-)%s%c*$') -- фильтр по игре if gam and #gam ~= 0 then gam = mw.text.trim(parseLinks(gam, 'link')1)-- only 1 game expected is if #gam 0 then gam = nil end else gam = nil end -- эта миссия уже была добавлена вручную? local handmade = findLoc(addEndParsed, {link = mis}) if not handmade and ((not gam or not game) or (gam and game and gam game)) then --mw.log(loc1, loc2) loc1 = parseLinks(loc1, 'table') loc2 = parseLinks(loc2, 'table') -- локация выполнения for i, v in ipairs(loc2) do local isInLoc1 = findLoc(loc1, v) if v.link ntitle.text then if isInLoc1 then -- если лока сдачи совпадает с локой взятия, -- то установить here loc1isInLoc1.here = true table.remove(loc2, i) break end table.insert(mend, '' .. mis .. '') end end-- for loc2 -- если лока сдачи не указана, то = локе взятия -- здесь нельзя определить конкретную локу из списка, потому - первая if #(loc2 or {}) 0 then loc11.here = true end -- локация взятия for i, v in ipairs(loc1) do -- миссия ссылается на текущую страницу? if v.link ntitle.text then table.insert(mstart, '' .. mis .. '' .. (v.here and there or '')) break end end-- for loc1 end-- if gam game end-- for line in dpllines end-- if dplresult -- process (sort etc) tables here table.sort(mstart, tableSort) table.sort(mend, tableSort) -- strip empty values table.insert(mstart, 1, '\n*Выдаются:') table.insert(mend, 1, '\n*Выполняются:') mstart = #mstart > 1 and table.concat(mstart, '\n**') or nil mend = #mend > 1 and table.concat(mend, '\n**') or nil -- какую надпись показать? if mstart then nret = mend and tfull or tin else nret = mend and tout or tnoresult end table.insert(nret1, nret) --table.insert(nret1, dplText) --table.insert(nret1, dplResult) table.insert(nret1, mstart) table.insert(nret1, mend) --return frame.preprocess and frame:preprocess(' ' .. table.concat(nret1, '\n----') .. ' ') or table.concat(nret1, '\n----') return table.concat(nret1) else -- заполнено вручную local ncontent = ntitle:getContent() local npattern = ' Задания .-' local findresult1, findresult2 = nil, nil findresult1 = mw.ustring.find(ncontent, npattern..'\n%*Выдаются', 1, false) findresult2 = mw.ustring.find(ncontent, npattern..'\n%*Выполняются', 1, false) if (findresult1 and findresult2) then nret = tfull elseif findresult1 then nret = tin elseif findresult2 then nret = tout end return nret end-- if mode auto end-- tlm function p.getParent (f) --returns top parent frame if f.getParent and f:getParent() then return p.getParent(f:getParent()) else return f end end function p.printarg (frame) --returns arg=value; order is not guaranteed local f = p.getParent(frame) local args = f.args local exclude = mw.text.split(frame.args.exclude or '', ',') local s = '' if exclude and #exclude 1 and #exclude1 0 then exclude = {} end function excluded (name) --returns true if param should be excluded if #exclude 0 then return false end for i, v in pairs(exclude) do if v name then return true end end return false end--excluded for i, v in pairs(args) do if not excluded(i) then --do not add = to unnamed and 1= s = s .. (tonumber(i) and '' or (i .. '=')) .. v end end return s end--printarg function p.dexname (frame) --return ext name local src = frame.args1 or frame.args'src' or '' local ext = nil if src '' then return end if mw.ustring.find(src, '\'\"\`UNIQ.-\-(.-)\-.-QINU\`\"\, 1, false) then ext = mw.ustring.gsub(mw.ustring.gsub(src, '\'\"\`UNIQ.-\-(.-)\-.-QINU\`\"\'', '%1'),'^(%s%c*)(.-)(%c%s*)$','%2') end return ext end --dexname function p.iif (cond, t, f) if cond then return t else return f end end function p.bit (b) return 2 ^ (b - 1) -- 1-based indexing end -- Typical call: if hasbit(x, bit(3)) then ... function p.hasbit (x, b) return x % (b + b) >= b end function p.setbit (x, b) return hasbit(x, b) and x or x + b end function p.clearbit (x, b) return hasbit(x, b) and x - b or x end function p_trim( s ) if s and not(s:match('^%s*$')) then return mw.text.trim( s ); -- If not nil nor empty. end end -- экспорт фигни для отладки p.parseLinks = parseLinks p.tableTrim = tableTrim p.tableSort = tableSort return p --